package org.liuping.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.liuping.common.constant.BasicConstant;
import org.liuping.common.utlis.EmailUtil;
import org.liuping.common.utlis.VerCodeGenerate;
import org.liuping.entity.UserEntity;
import org.liuping.exception.*;
import org.liuping.service.UserService;
import org.liuping.mapper.UserMapper;
import org.liuping.vo.UserLoginVo;
import org.liuping.vo.UserRegistryVo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
* @author liupi
* @description 针对表【t_users】的数据库操作Service实现
* @createDate 2023-03-30 11:28:54
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity>
    implements UserService {

    //公钥、私钥通过sa-token自动生成并配置在yml中
    @Value("${RSA.privateKey}")
    private String privateKey;
    @Value("${RSA.publicKey}")
    private String publicKey;

    @Resource
    private EmailUtil emailUtil;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    //判断登录
    @Override
    public void login(UserLoginVo userLoginVo) throws UsernamePasswordErrorException{

        //用户的名称或者email
        String account = userLoginVo.getAccount();
        String password = userLoginVo.getPassword();
        //传账户名称，查询数据库，比对信息进行登录(写sql)
        UserEntity userEntity = baseMapper.loginIn(account);
        String userEntityPassword = userEntity.getPassword();
        //利用私钥进行解密
        String decryptByPrivate = SaSecureUtil.rsaDecryptByPrivate(privateKey, userEntityPassword);

        if (decryptByPrivate.equals(password)){
            //解密后的密码与解密前相同,返回登录成功
            Object uid = userEntity.getUid();
            Boolean rememberMe = userLoginVo.getRememberMe();
            if ((rememberMe != null) && rememberMe){
                //关闭浏览器，登录不会失效，会保存7天（yml配置）
                StpUtil.login(uid,SaLoginConfig.setExtra("user",userEntity));
            }else {
                //关闭浏览器，登录失效
                StpUtil.login(uid,SaLoginConfig.setExtra("user",userEntity).setIsLastingCookie(false));
            }
        }else{
            //如果错误，则返回异常
            throw new UsernamePasswordErrorException();
        }

    }
    /**
     * 用户注册
     */
    @Override
    public void registry(UserRegistryVo userRegistryVo) throws PasswordConfirmException,UsernameOrEmailExistException,CodeErrorException{
        //获取接收到的值
        String password = userRegistryVo.getPassword();
        String confirmPassword = userRegistryVo.getConfirmPassword();
        if (!password.equals(confirmPassword)){
            //也可前端进行处理
            throw new PasswordConfirmException();
        }
        //判断这几个参数是否重复或正确
        String username = userRegistryVo.getUsername();
        String email = userRegistryVo.getEmail();
        String code = userRegistryVo.getCode();
        Long count = baseMapper.userExist(username,email);
        if (count > 0){
            //如果有返回值，则用户名或邮箱已存在
            throw new UsernameOrEmailExistException();
        }
        //比对code
        String redisCode = stringRedisTemplate.opsForValue().get(BasicConstant.EMAIL_CODE_PREFIX.getValue() + email);
        if (code.equals(redisCode.split("_")[0])){
            //将信息存入到数据库
            UserEntity userEntity = new UserEntity();
            //用rsa公钥加密密码
            String encryptByPublic = SaSecureUtil.rsaEncryptByPublic(publicKey, password);
            //设置属性userEntity
            userEntity.setEmail(email);
            userEntity.setPassword(encryptByPublic);
            userEntity.setUsername(username);
            baseMapper.insert(userEntity);
        }else {
            throw new CodeErrorException();
        }
    }
    //发送验证码
    @Override
    public void sendCode(String email) throws GetEmailCodeTooFastException {
        String redisEmailKey = BasicConstant.EMAIL_CODE_PREFIX.getValue() + email;
        //先验证是否存在验证码
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(redisEmailKey))){
            //取出验证码
            String redisExistCode = stringRedisTemplate.opsForValue().get(redisEmailKey);
            //转换成Long
            long time = Long.parseLong(redisExistCode.split("_")[1]);
            long currentTimeMillis = System.currentTimeMillis();
            if ((currentTimeMillis-time) < 60000){
                throw new GetEmailCodeTooFastException();
            }
        }
        //生成6位验证码
        String emailCode = VerCodeGenerate.generateVerCode();
        //加入当前时间，防止60s内再次发送验证码
        String redisEmailCode = emailCode + "_" + System.currentTimeMillis();
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        //存入redis，5分钟有效期，后面用于校验,要带上前缀
        ops.set(redisEmailKey, redisEmailCode,5,TimeUnit.MINUTES);
        //发送邮件
        emailUtil.sendMessage(email,"注册验证码","注册验证码为：" + emailCode + "，该验证码5分钟内有效");
    }
    //第三方调用userService进行注册
    @Override
    public UserEntity giteeOauthRegistry(UserRegistryVo userRegistryVo) {
        //先查询是否存在用户
        String username = userRegistryVo.getUsername();
        String email = userRegistryVo.getEmail();
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username).or().eq("email",email);
        UserEntity userEntity = baseMapper.selectOne(wrapper);
        if (userEntity == null){
            //如果用户不存在，则执行注册操作
            UserEntity user = new UserEntity();
            //设置属性user
            user.setEmail(email);
            user.setUsername(username);
            //如果有返回值，则用户名或邮箱已存在，则不用再进行注册
            baseMapper.insert(user);
            userEntity = user;
        }
        //mybatis-plus插入成功时自动注入id
        return userEntity;
    }
    //第三方调用登录功能
    @Override
    public void giteeOauthLogin(UserEntity userEntity) {
        Long uid = userEntity.getUid();
        //关闭浏览器，登录不会失效，会保存7天（yml配置）
        StpUtil.login(uid,SaLoginConfig.setExtra("user",userEntity));
    }
}




